
package com.hlkj.pay.app.merchant.ext.impl.heepay.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.hlkj.pay.app.merchant.IMerchantAccessAppService;
import com.hlkj.pay.app.merchant.ext.dto.report.ChannelMerchantReportContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessContext;
import com.hlkj.pay.app.merchant.ext.impl.MerchantAccessUploadFile;
import com.hlkj.pay.app.merchant.ext.impl.heepay.dto.HeePayConfig;
import com.hlkj.pay.common.MerchantResultCode;
import com.hlkj.pay.dto.merchant.MerchantAccessDto;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.dto.pay.PayCommonAppDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.*;
import com.hlkj.pay.infrastructure.model.pay.PayChannelDictDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.util.MerchantUtils;

import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.StringPool;
import okhttp3.OkHttpClient;

/**
 * 汇付 商户进件参数处理
 * 
 * @author HlpayTeam
 * @date 2024/09/26 12:02
 */
@Slf4j
@Service
public class HeePayMerchantParamsHandle extends HeePayMerchantCommonParamsHandle {

    @Autowired
    private OkHttpClient okHttpClient;

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public CommonResult<Void> merchantApplyParamsCheck(ChannelMerchantAccessContext channelMerchantAccessContext) {
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        MerchantAccessCardDO merchantAccessCard = merchantAccessDto.getMerchantAccessCard();
        MerchantAccessLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantAccessLicense();
        String name = merchantAccessBusiness.getShortName();
        String shortName = merchantAccessInfo.getName();

        List<ProviderChannelFeeConfigList> merchantFeeConfigList = channelMerchantAccessContext.getMerchantFeeConfigList();
        Map<Integer, List<ProviderChannelFeeConfigList>> merchantFeeConfigMap = merchantFeeConfigList.stream()
                .collect(Collectors.groupingBy(merchantFeeConfig -> merchantFeeConfig.getPayWayDO().getType()));
        switch (MerchantEnum.MERCHANT_TYPE.from(merchantAccessInfo.getType())) {
            case PERSONAL:
                List<String> fileUrls = merchantAccessBusiness.getFileUrls();
                if (CollectionUtils.isEmpty(fileUrls) || fileUrls.size() != 4) {
                    return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                            MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "汇付宝宝小微商户,其他附件内容错误");
                }
                break;
            default:
                if ("5".equals(merchantAccessLicense.getCompanyType())) {
                    fileUrls = merchantAccessBusiness.getFileUrls();
                    if (CollectionUtils.isEmpty(fileUrls) || fileUrls.size() != 4) {
                        return CommonResult.error(MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getCode(),
                                MerchantResultCode.MERCHANT_ACCESS_PARAMS_ERROR.getMsg() + "汇付宝宝个体工商户,其他附件内容错误");
                    }
                }

        }

        return CommonResult.success();
    }

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public Map<String, Object> merchantApplyParams(ChannelMerchantAccessContext channelMerchantAccessContext, HeePayConfig lakalaConfig) {
        Map<String, Object> params = new HashMap<>();
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        MerchantAccessCertInfoDO merchantAccessLegal = merchantAccessDto.getMerchantAccessLegal();
        MerchantAccessCertInfoDO merchantAccessContact = merchantAccessDto.getMerchantAccessContact();
        MerchantAccessCardDO merchantAccessCard = merchantAccessDto.getMerchantAccessCard();
        MerchantAccessLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantAccessLicense();
        params.put("if_sign", "1");
        switch (MerchantEnum.MERCHANT_TYPE.from(merchantAccessInfo.getType())) {
            case PERSONAL:
                params.put("customer_type", 3);
                params.put("customer_name", merchantAccessLegal.getName());
                params.put("bank_account_type", 2);
                params.put("register_type", "HEEPAY_BALANCE");
                break;
            default:
                switch (merchantAccessLicense.getCompanyType()) {
                    case "5":
                        params.put("customer_type", 2);
                        switch (MerchantEnum.CARD_TYPE.from(merchantAccessCard.getType())) {
                            case CORPORATE_ACCOUNT:
                                params.put("bank_account_type", 1);
                                break;
                            default:
                                params.put("bank_account_type", 2);
                        }
                        break;
                    default:
                        params.put("customer_type", 1);
                        params.put("bank_account_type", 1);
                }
                params.put("if_sign", 1);
                params.put("customer_name", merchantAccessLicense.getName());
                params.put("licence_code", merchantAccessLicense.getLicenseCode());
                if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantAccessLicense.getLicenseValidityType())) {
                    params.put("licence_valid_type", 2);
                }
                else {
                    params.put("licence_valid_type", 1);
                    params.put("licence_valid_end", date(merchantAccessLicense.getLicenseEndDate()));
                }
                params.put("licence_valid_begin", date(merchantAccessLicense.getLicenseBeginDate()));
                params.put("licence_region_code", merchantAccessLicense.getAreaCode());
                params.put("licence_address", merchantAccessLicense.getAddress());


                // 1 不传 默认 传
                if (lakalaConfig.getIsUploadRate() == null || lakalaConfig.getIsUploadRate() != 1) {
                    Map<String, String> rates = rates(channelMerchantAccessContext.getMerchantFeeConfigList());
                    Map<String, Object> rate = new HashMap<>();
                    rate.put("rate", rates);
                    params.put("heepay_info", JsonUtils.toJsonString(rate));
                }
        }
        params.put("customer_short_name", merchantAccessBusiness.getShortName());
        params.put("business_category_code", merchantAccessBusiness.getMcc());
        params.put("legal_name", merchantAccessLegal.getName());
        params.put("legal_id_card", merchantAccessLegal.getCertNo());
        if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantAccessLegal.getCertValidityType())) {
            params.put("legal_id_card_valid_type", 2);
        }
        else {
            params.put("legal_id_card_valid_type", 1);
            params.put("legal_id_card_valid_end", date(merchantAccessLegal.getCertEndDate()));
        }
        params.put("legal_id_card_type", certType(merchantAccessLegal.getCertType()));
        params.put("legal_id_card_valid_begin", date(merchantAccessLegal.getCertBeginDate()));
        params.put("legal_mobile", merchantAccessLegal.getPhone());

        params.put("manage_name", merchantAccessLegal.getName());
        params.put("manage_id_card", merchantAccessLegal.getCertNo());
        if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantAccessLegal.getCertValidityType())) {
            params.put("manage_id_card_valid_type", 2);
        }
        else {
            params.put("manage_id_card_valid_type", 1);
            params.put("manage_id_card_valid_end", date(merchantAccessLegal.getCertEndDate()));
        }
        params.put("manage_id_card_type", certType(merchantAccessLegal.getCertType()));
        params.put("manage_id_card_valid_begin", date(merchantAccessLegal.getCertBeginDate()));
        params.put("manage_mobile", merchantAccessLegal.getPhone());
        params.put("manage_region_code", merchantAccessBusiness.getAreaCode());
        params.put("manage_detail_address", merchantAccessLegal.getAddress());

        params.put("customer_phone", merchantAccessContact.getPhone());
        params.put("contact_name", merchantAccessContact.getName());
        params.put("contact_id_card", merchantAccessContact.getCertNo());
        if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantAccessContact.getCertValidityType())) {
            params.put("contact_id_card_valid_type", 2);
        }
        else {
            params.put("contact_id_card_valid_type", 1);
            params.put("contact_id_card_valid_end", date(merchantAccessContact.getCertEndDate()));
        }
        params.put("contact_id_card_type", certType(merchantAccessContact.getCertType()));
        params.put("contact_id_card_valid_begin", date(merchantAccessContact.getCertBeginDate()));
        params.put("contact_mobile", merchantAccessLegal.getPhone());
        params.put("contact_email", merchantAccessLegal.getOtherValue());
        params.put("bank_account_name", merchantAccessCard.getName());
        params.put("bank_card_no", merchantAccessCard.getCardNo());
        PayChannelDictDO payChannelDictDO = channelMerchantAccessContext.getPayChannelDictList().get(0);
        params.put("bank_name", payChannelDictDO.getDictDesc());
        params.put("bank_region_code", merchantAccessCard.getAreaCode());
        params.put("bank_branch_code", merchantAccessCard.getBranchCode());
        params.put("withdraw_type", "2");

        params.put("beneficiary_is_legal", 1);

        List<PayCommonAppDto> payCommonAppList = channelMerchantAccessContext.getPayCommonAppList();
        if (!CollectionUtils.isEmpty(payCommonAppList)) {
            List<String> appIds = payCommonAppList.stream()
                    .filter(payCommonAppDto -> (payCommonAppDto.getType().equals(CommonEnum.COMMON_APP_TYPE.WECHAT_MIN.getType())
                            || payCommonAppDto.getType().equals(CommonEnum.COMMON_APP_TYPE.WECHAT_PUB.getType())))
                    .map(payCommonAppDto -> payCommonAppDto.getAppId()).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(appIds)) {
                params.put("wechat_small_app_id", StringUtils.collectionToDelimitedString(appIds, ","));
            }
        }
        channelMerchantAccessContext.getMerchantAccessUploadFiles().stream().forEach(merchantAccessUploadFile -> {
            params.put(merchantAccessUploadFile.getFieldName(), merchantAccessUploadFile.getFileId());
        });

        return params;

    }

    Map<String, String> rates(List<ProviderChannelFeeConfigList> merchantFeeConfigList) {
        Map<String, String> rate = new HashMap<>();
        for (ProviderChannelFeeConfigList merchantFeeConfig : merchantFeeConfigList) {
            if (CommonEnum.YES_NO_TYPE.YES.getCode().equals(merchantFeeConfig.getStatus())) {
                String key = null;

                PayWayDO payWayDO = merchantFeeConfig.getPayWayDO();
                PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
                if (!StringUtils.hasText(payWayDO.getSubType())) {
                    continue;
                }
                PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.fromByType(payWayDO.getSubType());
                if (scenePayType == null) {
                    continue;
                }
                if (payType == null) {
                    continue;
                }
                switch (payType) {
                    case WECHAT:
                        switch (scenePayType) {
                            case JSAPI:
                                key = "WX_JSAPI";
                                break;
                            case QR:
                                key = "WX_QRCODE";
                                break;
                            // case APP:
                            // key = "WX_APP";
                            // break;
                            // case SCAN:
                            // key = "WX_BARCODE";
                            // break;
                            // case H5:
                            // key = "WX_H5";
                            // break;
                            case MINI_APP:
                                key = "WX_MINI";
                                break;
                            default:
                                continue;

                        }
                        break;
                    case ALIPAY:
                        switch (scenePayType) {
                            // case SCAN:
                            // key = "ALI_BARCODE";
                            // break;
                            case QR:
                                key = "ALI_QRCODE";
                                break;
                            // case H5:
                            // key = "ALI_H5";
                            // break;
                            case JSAPI:
                                key = "ALI_JSAPI";
                                break;
                            case MINI_APP:
                                key = "ALI_MINI";
                                break;
                            default:
                                continue;
                        }
                        break;
                    case UNION_APY:
                        switch (scenePayType) {
                            case QR:
                                key = "BANK_QRCODE_SMALL_DEBIT";
                                break;
                            case H5:
                                key = "UNIPAY_H5_DEBIT";
                                break;
                            case APP:
                                key = "UNIPAY_APP_DEBIT";
                                break;
                            default:
                                continue;
                        }
                        break;
                    default:
                }
                if (merchantFeeConfig.getDefaultFeeConfigValue() != null && merchantFeeConfig.getDefaultFeeConfigValue().getRateBase() != null) {
                    rate.put(key, MerchantUtils.bigDecimalToString(merchantFeeConfig.getDefaultFeeConfigValue().getRateBase().divide(new BigDecimal(100))));
                }
            }
        }
        return rate;
    }

    /**
     * 新增文件参数转换
     *
     * @param channelMerchantAccessContext
     */
    public void addProcessFileId(ChannelMerchantAccessContext channelMerchantAccessContext, HeePayConfig lakalaConfig) {
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantAccessLicense();
        MerchantAccessCertInfoDO merchantAccessCert = merchantAccessDto.getMerchantAccessLegal();
        MerchantAccessCardDO merchantAccessCard = merchantAccessDto.getMerchantAccessCard();
        PayChannelRequestDO beforeMerchantAccessRequestDO = channelMerchantAccessContext.getBeforePayChannelRequestDO();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        MerchantAccessCertInfoDO merchantAccessContact = merchantAccessDto.getMerchantAccessContact();
        // 配置转换
        boolean test = channelMerchantAccessContext.isTest();
        Map<String, String> fileMap = new HashMap<>();
        if (beforeMerchantAccessRequestDO != null && StringUtils.hasText(beforeMerchantAccessRequestDO.getFileParams())) {
            fileMap = JsonUtils.parseObject(beforeMerchantAccessRequestDO.getFileParams(), Map.class);
        }
        try {
            // 营业执照 01
            // 开户许可证/开户证明照 02
            // 门头照 03
            // 店内场景照 04
            // 收银台照 05
            // 法人身份证正面照 06
            // 法人身份证反面照 07
            // 联系人身份证正面照 08
            // 联系人身份证反面照 09
            // 公司大楼照 10
            // 公司前台照 11
            // 结算银行卡正面照 12
            // 结算银行卡反面照 13
            // 结算人手持银行卡正面照 14
            // 经营者身份证正面照 15
            // 经营者身份证反面照 16
            // 经营者手持身份证正面照 17
            // 经营者手持银行卡正面照 18
            // 其它图片1 19
            // 其它图片2 20
            // 开户意愿视频 50
            // 分账协议 52
            List<MerchantAccessUploadFile> merchantAccessUploadFiles = new ArrayList<>();
            if (merchantAccessLicense != null) {
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("01").fileUrl(merchantAccessLicense.getLicenseUrl()).fieldName("licence_img").build());
            }
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("02").fileUrl(merchantAccessCard.getLicenseUrl()).fieldName("reg_certificate_img").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("03").fileUrl(merchantAccessBusiness.getStoreHeaderUrl()).fieldName("shop_front_img").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("04").fileUrl(merchantAccessBusiness.getStoreIndoorUrl()).fieldName("shop_env_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("05").fileUrl(merchantAccessBusiness.getStoreCashierDeskUrl()).fieldName("shop_cashier_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("06").fileUrl(merchantAccessCert.getCertFrontUrl()).fieldName("legal_id_card_front_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("07").fileUrl(merchantAccessCert.getCertBackUrl()).fieldName("legal_id_card_back_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("08").fileUrl(merchantAccessContact.getCertFrontUrl()).fieldName("contact_id_card_front_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("09").fileUrl(merchantAccessContact.getCertBackUrl()).fieldName("contact_id_card_back_img").build());
            merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("12").fileUrl(merchantAccessCard.getSettleCardFrontUrl()).fieldName("bank_front_img").build());
            List<String> fileUrls = merchantAccessBusiness.getFileUrls();
            // 1 结算银行卡背面（个体/小微）
            // 2 结算银行卡所有者手持银行卡正面图片（个体/小微）
            // 3 法人手持身份证正面（个体/小微）
            // 4 法人手持银行卡卡号（个体/小微）
            if (!CollectionUtils.isEmpty(fileUrls) && fileUrls.size() == 4) {
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("13").fileUrl(fileUrls.get(0)).fieldName("bank_back_img").build());
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("14").fileUrl(fileUrls.get(1)).fieldName("bank_owner_hold_img").build());
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("17").fileUrl(fileUrls.get(2)).fieldName("manage_hold_id_card_front_img").build());
                merchantAccessUploadFiles.add(MerchantAccessUploadFile.builder().fileKey("18").fileUrl(fileUrls.get(3)).fieldName("manage_hold_bank_front_img").build());
            }
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("15").fileUrl(merchantAccessContact.getCertFrontUrl()).fieldName("manage_id_card_front_img").build());
            merchantAccessUploadFiles
                    .add(MerchantAccessUploadFile.builder().fileKey("16").fileUrl(merchantAccessContact.getCertBackUrl()).fieldName("manage_id_card_back_img").build());

            for (MerchantAccessUploadFile merchantAccessUploadFile : merchantAccessUploadFiles) {
                CommonResult<Void> f07 = fileUploadProcess(fileMap, lakalaConfig, merchantAccessUploadFile, test);
                if (!f07.isSuccess()) {
                    channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
                    channelMerchantAccessContext.setRemark(f07.getMsg());
                    return;
                }
            }
            channelMerchantAccessContext.setMerchantAccessUploadFiles(merchantAccessUploadFiles);
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        finally {
            PayChannelRequestDO payChannelRequestDO = channelMerchantAccessContext.getPayChannelRequestDO();
            if (payChannelRequestDO == null) {
                payChannelRequestDO = new PayChannelRequestDO();
            }
            payChannelRequestDO.setFileParams(JsonUtils.toJsonString(fileMap));
            channelMerchantAccessContext.setPayChannelRequestDO(payChannelRequestDO);
        }
    }

    public CommonResult<Void> fileUploadProcess(Map<String, String> fileMap, HeePayConfig lakalaConfig, MerchantAccessUploadFile merchantAccessUploadFile, boolean test) {
        if (!StringUtils.hasText(merchantAccessUploadFile.getFileUrl())) {
            return CommonResult.success();
        }
        String fileKey = merchantAccessUploadFile.getFileUrl().hashCode() + "_" + merchantAccessUploadFile.getFileKey();
        String fileId = fileMap.get(fileKey);
        if (StringUtils.hasText(fileId)) {
            log.info("heepay文件映射获取成功 fileUrl:{},fileId:{}", merchantAccessUploadFile.getFileUrl(), fileId);
            merchantAccessUploadFile.setFileId(fileId);
            return CommonResult.success();
        }
        log.info("heepay文件映射获取未成功 fileType:{}, fileUrl:{}", test, merchantAccessUploadFile.getFileUrl());
        CommonResult<Void> f371 = fileUpload(merchantAccessUploadFile, lakalaConfig, test);
        if (f371.isSuccess()) {
            fileMap.put(fileKey, merchantAccessUploadFile.getFileId());
        }
        return f371;
    }

    /**
     * 文件上传
     *
     * @param merchantAccessUploadFile
     * @param heePayConfig
     * @return
     * @throws Exception
     */
    public CommonResult<Void> fileUpload(MerchantAccessUploadFile merchantAccessUploadFile, HeePayConfig heePayConfig, boolean test) {
        if (!file(merchantAccessUploadFile.getFileUrl())) {
            log.info("文件格式错误 跳过文件上传:fileUrl:{},test:{}", merchantAccessUploadFile.getFileUrl(), test);
            return CommonResult.success();
        }
        CommonResult<Map<String, String>> commonResult = fileUploadRequest(merchantAccessUploadFile, heePayConfig, test);
        if (commonResult.isSuccess()) {
            merchantAccessUploadFile.setFileId(commonResult.getData().get("file_id"));
            return CommonResult.success();
        }
        return CommonResult.error(commonResult.getCode(), commonResult.getMsg());
    }

    public static boolean file(String fileUrl) {
        if (!StringUtils.hasText(fileUrl)) {
            return false;
        }
        int indexOf = fileUrl.lastIndexOf(StringPool.SLASH);
        if (indexOf < 0) {
            return false;
        }
        String fileType = fileUrl.substring(indexOf);
        if (!fileType.contains(StringPool.DOT)) {
            return false;
        }
        return true;
    }

}
